#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <resolv.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define NOOF_SOCKETS 100

int main(int argv, char** argc){

	int host_port= 1101;

	int i;

	int socketlist[NOOF_SOCKETS]={0};
	char socketbuffer[NOOF_SOCKETS][100];
	int socketcounter=0;
	int highestsocket=0;

	struct sockaddr_in my_addr;

	int hsock;
	int * p_int ;

	socklen_t addr_size = 0;
	sockaddr_in sadr;

	fd_set  rFd, rFdx;
	fd_set  eFd, eFdx;
	fd_set  wFd, wFdx;


	hsock = socket(AF_INET, SOCK_STREAM, 0);
	if(hsock == -1){
		printf("Error initializing socket %d\n", errno);
		goto FINISH;
	}
	
	p_int = (int*)malloc(sizeof(int));
	*p_int = 1;
		
	if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
		(setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
		printf("Error setting options %d\n", errno);
		free(p_int);
		goto FINISH;
	}
	free(p_int);

	/* Set the socket in non blocking mode */
        if(fcntl(hsock, F_SETFL, O_NONBLOCK)==-1){
		printf("Error setting in non-block %d",errno );
		goto FINISH;
	}


	my_addr.sin_family = AF_INET ;
	my_addr.sin_port = htons(host_port);
	
	memset(&(my_addr.sin_zero), 0, 8);
	my_addr.sin_addr.s_addr = INADDR_ANY ;
	
	if( bind( hsock, (sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
		fprintf(stderr,"Error binding to socket, make sure nothing else is listening on this port %d\n",errno);
		goto FINISH;
	}
	if(listen( hsock, 10) == -1 ){
		fprintf(stderr, "Error listening %d\n",errno);
		goto FINISH;
	}

	//Now lets do the server stuff
	FD_ZERO(&rFd);
	FD_ZERO(&eFd);
	FD_ZERO(&wFd);

	addr_size = sizeof(sockaddr_in);

	int retv;
	int csock;

	FD_SET(hsock, &rFd);
	FD_SET(hsock, &eFd);
	FD_SET(hsock, &wFd);

	while(true){

		memcpy(&rFdx, &rFd, sizeof(rFd));
                memcpy(&wFdx, &wFd, sizeof(wFd));
		memcpy(&eFdx, &eFd, sizeof(eFd));

		if( (retv = select((hsock<highestsocket?highestsocket:hsock)+1, &rFdx, &wFdx, &eFdx, 0) ) > 0){
			if(FD_ISSET(hsock, &rFdx)){
				if((csock = accept( hsock, (sockaddr*)&sadr, &addr_size))!= -1){
					printf("---------------------\nReceived connection from %s\n",inet_ntoa(sadr.sin_addr));
					socketlist[socketcounter++]= csock;
					if(csock > highestsocket)
					       highestsocket=csock;	
					FD_SET(csock, &rFd);
					FD_SET(csock, &eFd);
				}
			}
			for(i=0;i<socketcounter;i++){
				if(socketlist[i]){
				 	if(FD_ISSET(socketlist[i], &rFdx)){
						int recvbytes;
						switch(recvbytes=recv(socketlist[i], socketbuffer[i], 100,0)){
						case -1: 
							printf("Read Error\n");
							FD_CLR(socketlist[i], &rFd);
							FD_CLR(socketlist[i], &eFd);
							socketlist[i]=0;
							break;
						case 0:
							printf("Socket closed\n");
							FD_CLR(socketlist[i], &rFd);
							FD_CLR(socketlist[i], &eFd);
							socketlist[i]=0;
							break;
						default:
							printf( "Read %d bytes from %d\n", recvbytes, socketlist[i]);	
							socketbuffer[i][recvbytes]='\0';
							FD_SET(socketlist[i], &wFd);
						}
					}
				 	if(FD_ISSET(socketlist[i], &wFdx)){
						int writebytes;
						if((writebytes=send(socketlist[i], socketbuffer[i], strlen(socketbuffer[i]), 0))>0){
							printf("Sent %d bytes to %d\n", writebytes, socketlist[i]);
							FD_CLR(socketlist[i], &wFd);
						}
						else{
							printf("Write Error\n");
							FD_CLR(socketlist[i], &rFd);
							FD_CLR(socketlist[i], &wFd);
							FD_CLR(socketlist[i], &eFd);
							socketlist[i]=0;
						}
					}
				}
			}
		}
	}
	
FINISH:
;
}
/*
void* SocketHandler(void* lp){
    int *csock = (int*)lp;

	char buffer[1024];
	int buffer_len = 1024;
	int bytecount;

	memset(buffer, 0, buffer_len);
	if((bytecount = recv(*csock, buffer, buffer_len, 0))== -1){
		fprintf(stderr, "Error receiving data %d\n", errno);
		goto FINISH;
	}
	printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
	strcat(buffer, " SERVER ECHO");

	if((bytecount = send(*csock, buffer, strlen(buffer), 0))== -1){
		fprintf(stderr, "Error sending data %d\n", errno);
		goto FINISH;
	}
	
	printf("Sent bytes %d\n", bytecount);


FINISH:
	free(csock);
    return 0;
}
*/
